home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / ColorSync 2.5.1 SDK / Sample Code / CSDemo 2.5 / CSDemoSources / myDrawMatchedPict.c < prev    next >
Encoding:
Text File  |  1998-09-09  |  31.4 KB  |  1,025 lines  |  [TEXT/CWIE]

  1. // a different implimentation of NCMDrawMatchedPicture
  2. //
  3. // David Hayward 
  4. // Developer Technical Support
  5. // AppleLink: DEVSUPPORT
  6. //
  7. // Copyright 1995-1998, Apple Computer,Inc
  8. // 
  9. // 12/13/94    david    first cut
  10. // 12/13/94    david    fixed which caused 16-bit picts to crash because pict was not
  11. //                    locked in memory
  12. //  9/25/97    ebb        mods to keep track of ticks and pixel counts
  13. //
  14. // The ColorSync 1.0 DrawMatchedPicture, does not use bottlenecks as one might expect.
  15. // It installs a bottleneck routine for PicComments (so that it can watch the
  16. // embedded profiles go by) but does not do the actual matching in bottleneck routines.
  17. // Instead, It installs a ColorSearchProc in the current GDevice.  Inside the
  18. // ColorSearchProc, each color is matched - one at a time.  This implementation has
  19. // some advantages but one big problem is that it is painfully slow on PixMaps because,
  20. // even if the PixMap only contains 16 colors, each pixel is matched.
  21. //
  22. // This has been changed in CS 2.0.  In order to boost performance of PixMaps (which are,
  23. // after all, quite common) are now matched in the bottleneck instead of the ColorSearchProc.
  24. //
  25. // Interesting side note:
  26. // If you record DrawMatchedPicture (in the case of CS1) or NCMDrawMatchedPicture (in the
  27. // case of CS2) into another picture using the following code:
  28. //   *newPict = OpenPicture( &pictRect ) ;  // start recording
  29. //   NCMDrawMatchedPicture( pict, destProf, &pictRect ) ;
  30. //   ClosePicture() ;   // stop recording
  31. // then the resulting newPict will contain the same data as the original pict.  It does
  32. // not contain the matched picture information as you might suspect.
  33. //
  34. //
  35. // This file contains a different implimentation of NCMDrawMatchedPicture. 
  36. // it differs from  NCMDrawMatchedPicture in that it uses bottleneck
  37. // procs to do all the matching instead of installing ColorSearchProc
  38. // This meens that if you record myDrawMatchedPicture in another picture,
  39. // then the resulting picture will contain the mached color and may be considerably
  40. // smaller because it does not contain any profiles.  myDrawMatchedPicture
  41. // allows an application to pre-match a picture once, and then use the resulting pict
  42. // for fast updates.  Of course, if the source or dest profiles are changed then the pict
  43. // will need to be re-matched.
  44. //
  45. // This file also contains two other routines which share a lot of code of myDrawMatchedPicture
  46. //   myDrawProofoedPicture - matches a pict according to 3 profiles (source to destination
  47. //      to preview) so that you can do a print-preview of the color output
  48. //   myDrawCheckedPicture - gamut checks a pict according to the source and printer profiles
  49. //      the resulting pict is black for all points out of gamut and white everywhere else
  50. //
  51. // This certainly not fully polished yet, being as that I have only tested
  52. // it out on only a handful of pict files and profiles.
  53.  
  54.  
  55. #include <QuickDraw.h>
  56. #include <QDOffscreen.h>
  57. #include <CMApplication.h>
  58.  
  59. #include "qdUtils.h"
  60. #include "colorsyncUtils.h"
  61. #include "myDrawMatchedPict.h"
  62.  
  63. /**\
  64. |**| ==============================================================================
  65. |**| PRIVATE DEFINES
  66. |**| ==============================================================================
  67. \**/
  68. #define kMatch        1
  69. #define kProof        2
  70. #define kCheck        3
  71.  
  72. #define kForeColor    1
  73. #define kBackColor    2
  74.  
  75. #define kPenPixPat    1
  76. #define kFillPixPat    2
  77. #define kBackPixPat    3
  78.  
  79.  
  80. /**\
  81. |**| ==============================================================================
  82. |**| PRIVATE GLOBALS
  83. |**| ==============================================================================
  84. \**/
  85. static OSErr             gError                        = noErr ;
  86. static unsigned long    gTicks                        = 0;
  87. static unsigned long    gPixels                        = 0;
  88. static CMWorldRef         gCW                            = nil;
  89. static CMProfileRef        gSrceProf                    = nil;
  90. static CMProfileRef        gDestProf                    = nil;
  91. static CMProfileRef        gPrevProf                    = nil;
  92. static short            gDrawMode                    = 0;
  93. static Boolean            gMatchingEnabled            = true ;
  94. static unsigned long     gCount                        = 0;
  95. static PicHandle        gPict                        = nil ;
  96.  
  97. static RGBColor            gWhiteRGB                    = { 0xFFFF,0xFFFF,0xFFFF } ;
  98. static RGBColor            gBlackRGB                    = { 0x0000,0x0000,0x0000 } ;
  99.  
  100. // Match Buffers
  101. static RGBColor            gLastForeColor ;
  102. static RGBColor            gLastForeColorMatched ;
  103. static Boolean            gLastForeColorNeedsUpdate ;
  104. static RGBColor            gLastBackColor ;
  105. static RGBColor            gLastBackColorMatched ;
  106. static Boolean            gLastBackColorNeedsUpdate ;
  107. static PixPatHandle        gLastPenPixPat ;
  108. static PixPatHandle        gLastFillPixPat ;
  109. static PixPatHandle        gLastBackPixPat ;
  110.  
  111. // Profile Buffers
  112. static CMProfileRef**    gProfileListHdl ;
  113. static long                gProfileListCount ;
  114.  
  115. /**\
  116. |**| ==============================================================================
  117. |**| PRIVATE FUNCTION PROTOTYPES
  118. |**| ==============================================================================
  119. \**/
  120. void    SetError                ( OSErr err ) ;
  121. Boolean SameColor                ( RGBColor *rgbA, RGBColor *rgbB ) ;
  122. CMError    ChangeRGBColor            ( RGBColor *rgb ) ;
  123. void    ChangePortColor            ( short which ) ;
  124. void    UnChangePortColor        ( short which ) ;
  125.  
  126. CMError    ChangePixPat            ( PixPatHandle pat ) ;
  127. void    ChangePortPixPat        ( short which ) ;
  128. void    UnChangePortPixPat        ( short which ) ;
  129.  
  130. void    ChangePortPixPatForVerb    ( GrafVerb verb ) ;
  131. void    UnChangePortPixPatForVerb( GrafVerb verb ) ;
  132.  
  133. pascal void        TextProc        ( short byteCount, Ptr textAddr, Point numer, Point denom ) ;
  134. pascal void        LineProc        ( Point endPoint ) ;
  135. pascal void        RectProc        ( GrafVerb verb, Rect *r ) ;
  136. pascal void        RRectProc        ( GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight ) ;
  137. pascal void        OvalProc        ( GrafVerb verb, Rect *r ) ;
  138. pascal void        ArcProc            ( GrafVerb verb, Rect *r, short startAngle, short arcAngle ) ;
  139. pascal void        PolyProc        ( GrafVerb verb, PolyHandle poly ) ;
  140. pascal void        RgnProc            ( GrafVerb verb, RgnHandle rgn ) ;
  141. pascal void        BitsProc        ( BitMap *bitPtr, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn ) ;
  142. pascal void        CommentProc        ( short kind, short dataSize, Handle dataHandle ) ;
  143.  
  144. void    DisposeColorWorld        ( void ) ;
  145. void    BuildColorWorld            ( CMProfileRef srceProf ) ;
  146.  
  147. OSErr    AllocateProfileBuffers    ( void ) ;
  148. OSErr    AppendProfileBuffers    ( CMProfileRef prof ) ;
  149. void    DisposeProfileBuffers    ( void ) ;
  150.  
  151. OSErr    AllocateMatchBuffers    ( void ) ;
  152. void    DisposeMatchBuffers        ( void ) ;
  153.  
  154. OSErr    myDrawPicture            (    PicHandle pict,
  155.                                     CMProfileRef srceProf,
  156.                                     CMProfileRef destProf,
  157.                                     CMProfileRef prevProf,
  158.                                     Rect *rect,
  159.                                     unsigned long *ticks,
  160.                                     unsigned long *pixels ) ;
  161.                                     
  162. short    CalculateRowBytesFromRect ( Rect *theRect, short pixelSize) ;
  163.  
  164.  
  165.  
  166. /*------------------------------------------------------------------------------*\
  167.     SetError
  168.  *------------------------------------------------------------------------------*
  169.         This routine sets the current error state globalif it hasn't be set already.
  170. \*------------------------------------------------------------------------------*/
  171. static void SetError ( OSErr err )
  172. {
  173.     if ( (gError==noErr) && (err!=noErr) )
  174.         gError = err ;
  175. }
  176.  
  177.  
  178. /*------------------------------------------------------------------------------*\
  179.     SetError
  180.  *------------------------------------------------------------------------------*
  181.         This routine returns true if two colors have tha same RGB values.
  182. \*------------------------------------------------------------------------------*/
  183. static Boolean SameColor ( RGBColor *rgbA, RGBColor *rgbB )
  184. {
  185.     return    (    (rgbA->red   == rgbB->red) &&
  186.                 (rgbA->green == rgbB->green) &&
  187.                 (rgbA->blue  == rgbB->blue) ) ;
  188. }
  189.  
  190.  
  191. /*------------------------------------------------------------------------------*\
  192.     ChangeRGBColor
  193.  *------------------------------------------------------------------------------*
  194.         This routine changes an RGBColor according to the current state if the 
  195.         gDrawMode, gMatchingEnabled, and gCW globals.  If the gDrawMode is kCheck
  196.         the the color is gamut checked according to the gCW color world.  If the
  197.         gDrawMode is kMatch or kProof, then the color is matched according to
  198.         the gCW color world.
  199. \*------------------------------------------------------------------------------*/
  200. static CMError ChangeRGBColor ( RGBColor *rgb )
  201. {
  202.     CMColor        cmcolor ;
  203.     CMError        cmerr=noErr ;
  204.     long        result=0 ;
  205.  
  206.     if (gDrawMode != kCheck)                    // if these two conditions are true
  207.     if (gMatchingEnabled == false) return noErr;// then no work needs to be done
  208.  
  209.     cmcolor.rgb.red   = rgb->red ;
  210.     cmcolor.rgb.green = rgb->green ;
  211.     cmcolor.rgb.blue  = rgb->blue ;
  212.  
  213.     if (gDrawMode == kCheck)
  214.     {
  215.         if (gMatchingEnabled)
  216.         {
  217.             cmerr = CWCheckColors( gCW, &cmcolor, 1, &result) ;
  218.             if (result)
  219.                 cmcolor.rgb.red = cmcolor.rgb.green = cmcolor.rgb.blue = 0x0000 ;// black
  220.             else
  221.                 cmcolor.rgb.red = cmcolor.rgb.green = cmcolor.rgb.blue = 0xFFFF ;// white
  222.         }
  223.         else
  224.             cmcolor.rgb.red = cmcolor.rgb.green = cmcolor.rgb.blue = 0xFFFF ;// white
  225.     }
  226.     else
  227.         if (gMatchingEnabled)
  228.             cmerr = CWMatchColors( gCW, &cmcolor, 1 ) ;
  229.     
  230.     if ( cmerr ) return cmerr ;
  231.     
  232.     rgb->red   = cmcolor.rgb.red ;
  233.     rgb->green = cmcolor.rgb.green ;
  234.     rgb->blue  = cmcolor.rgb.blue ;
  235.  
  236.     return cmerr;
  237. }
  238.  
  239.  
  240. /*------------------------------------------------------------------------------*\
  241.     ChangePortColor
  242.  *------------------------------------------------------------------------------*
  243.         This routine changes one of the RGBColors in the current CGrafPort by
  244.         calling ChangeRGBColor().  For example, if which==kForeColor then the port's
  245.         rgbFgColor is changed.  The color before and after the change is buffered
  246.         in globals so that, if the the the next object to be drawn uses the same
  247.         color, then the change can be done quickly.
  248. \*------------------------------------------------------------------------------*/
  249. static void ChangePortColor ( short which )
  250. {
  251.     RGBColor    *curentColor ;
  252.     RGBColor    *lastColor ;
  253.     RGBColor    *lastColorMatched ;
  254.     Boolean        *lastColorNeedsUpdate ;
  255.     CMError        cmerr=noErr ;
  256.  
  257.     if (gDrawMode != kCheck)                            // if these two conditions are true
  258.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  259.  
  260.     switch (which)
  261.     {
  262.         case kForeColor :
  263.             curentColor = &(((CGrafPtr)qd.thePort)->rgbFgColor) ;
  264.             lastColor = &gLastForeColor ;
  265.             lastColorMatched = &gLastForeColorMatched ;
  266.             lastColorNeedsUpdate = &gLastForeColorNeedsUpdate  ;
  267.             break ;
  268.         case kBackColor :
  269.             curentColor = &(((CGrafPtr)qd.thePort)->rgbBkColor) ;
  270.             lastColor = &gLastBackColor ;
  271.             lastColorMatched = &gLastBackColorMatched ;
  272.             lastColorNeedsUpdate = &gLastBackColorNeedsUpdate ;
  273.             break ;
  274.         default :
  275.             return ;
  276.             break ;
  277.     }
  278.                 
  279.     if ( SameColor( lastColor, curentColor ) )
  280.     {
  281.         if ( *lastColorNeedsUpdate )
  282.             cmerr = ChangeRGBColor( curentColor ) ;
  283.         else
  284.             *curentColor = *lastColorMatched ;            // current = lastMatched
  285.     }
  286.     else
  287.     {
  288.         *lastColor = *curentColor ;                        // last = curent
  289.         cmerr = ChangeRGBColor( curentColor ) ;            // match curent
  290.     }
  291.     
  292.     if (!cmerr)
  293.     {
  294.         *lastColorMatched = *curentColor ;                // lastMatched = curent
  295.         *lastColorNeedsUpdate = false ;
  296.     }
  297.     SetError( cmerr ) ;
  298. }
  299. /*------------------------------------------------------------------------------*\
  300.     UnChangePortColor
  301.  *------------------------------------------------------------------------------*
  302.         This routine un-changes one of the RGBColors in the current CGrafPort by
  303.         by restoring the appropriate buffered global.
  304. \*------------------------------------------------------------------------------*/
  305. static void UnChangePortColor ( short which )
  306. {
  307.     if (gDrawMode != kCheck)                            // if these two conditions are true
  308.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  309.  
  310.     switch (which)
  311.     {
  312.         case kForeColor :
  313.             (((CGrafPtr)qd.thePort)->rgbFgColor) = gLastForeColor ;
  314.             break ;
  315.         case kBackColor :
  316.             (((CGrafPtr)qd.thePort)->rgbBkColor) = gLastBackColor ;
  317.             break ;
  318.         default :
  319.             break ;
  320.     }
  321. }
  322.  
  323.  
  324.  
  325. ////////////////////////////////////////////////////////////////////////////////
  326.  
  327.  
  328. /*------------------------------------------------------------------------------*\
  329.     ChangePixPat
  330.  *------------------------------------------------------------------------------*
  331.         This routine changes an PixPat according to the current state if the 
  332.         gDrawMode, gMatchingEnabled, and gCW globals.  If the gDrawMode is kCheck
  333.         the the PixPat is gamut checked according to the gCW color world.  If the
  334.         gDrawMode is kMatch or kProof, then the PixPat is matched according to
  335.         the gCW color world.
  336.     ** NOTE **
  337.         this routine still needs work so that it can properly hanlde type-1 and
  338.         type-2 PixMaps.  The commented psuedo-code is a rought outline of what
  339.         needs to be added.
  340. \*------------------------------------------------------------------------------*/
  341. static CMError ChangePixPat ( PixPatHandle pat )
  342. {
  343.     CMError        cmerr=noErr;
  344.     
  345.     if (gDrawMode != kCheck)                            // if these two conditions are true
  346.     if (gMatchingEnabled == false) return noErr;        // then no work needs to be done
  347.     
  348.     switch ((**pat).patType)
  349.     {
  350.         case 0:        /* one-bit patterns are drawn in the foreground and background color. */
  351.             ChangePortColor( kForeColor ) ;
  352.             ChangePortColor( kBackColor ) ;
  353.             break;
  354.         case 1:        /* Type 1 PixPats have a color table. */
  355.             if (gDrawMode == kCheck)
  356.             {
  357.                 if (gMatchingEnabled)
  358.                 {
  359.                     // if pat is indexed
  360.                     //   CWCheckPixMap()
  361.                     //   copy bitbap from above into a new pattern
  362.                     // else
  363.                     //   if pat doesn't have a full color table
  364.                     //     fill in the extra entries with colors between fg and bk
  365.                     //   for each color in table
  366.                     //     ChangeRGBColor()
  367.                 }
  368.                 else
  369.                 {
  370.                     // make pat white ;// white
  371.                 }
  372.             }
  373.             else
  374.             {
  375.                 if (gMatchingEnabled)
  376.                 {
  377.                     // if pat is indexed and doesn't has a full color table
  378.                     //      fill in the extra entries with colors between fg and bk
  379.                     cmerr = CWMatchPixMap( gCW, (*(**pat).patMap), nil, nil ) ;
  380.                 }
  381.             }
  382.             PixPatChanged( pat ) ;
  383.             break;
  384.         case 2:        /* Type 2 PixPats have 5 color entries where the 5th is the desired color */
  385.             // ChangeRGBColor() to chane the 5th colortable entry
  386.             PixPatChanged( pat ) ;
  387.             break;
  388.     }
  389.     return cmerr ;
  390. }
  391.  
  392.  
  393. /*------------------------------------------------------------------------------*\
  394.     ChangePortPixPat
  395.  *------------------------------------------------------------------------------*
  396.         This routine changes one of the PixPats in the current CGrafPort by
  397.         calling ChangePixPat().  For example, if which==kPenPixPat then the port's
  398.         pnPixPat is changed.  The PixPat before the change is buffered in a
  399.         global so that it is posible to restore the orginal PixPat quickly.
  400. \*------------------------------------------------------------------------------*/
  401. static void ChangePortPixPat ( short which )
  402. {
  403.     PixPatHandle    *curentPixPat ;
  404.     PixPatHandle    *lastPixPat ;
  405.     CMError            cmerr=noErr ;
  406.  
  407.     if (gDrawMode != kCheck)                            // if these two conditions are true
  408.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  409.  
  410.     switch (which)
  411.     {
  412.         case kPenPixPat :
  413.             curentPixPat = &(((CGrafPtr)qd.thePort)->pnPixPat) ;
  414.             lastPixPat = &gLastPenPixPat ;
  415.             break ;
  416.         case kFillPixPat :
  417.             curentPixPat = &(((CGrafPtr)qd.thePort)->fillPixPat) ;
  418.             lastPixPat = &gLastFillPixPat ;
  419.             break ;
  420.         case kBackPixPat :
  421.             curentPixPat = &(((CGrafPtr)qd.thePort)->bkPixPat) ;
  422.             lastPixPat = &gLastBackPixPat ;
  423.             break ;
  424.         default :
  425.             return ;
  426.             break ;
  427.     }
  428.  
  429.     CopyPixPat( *curentPixPat, *lastPixPat) ;            // last = curent
  430.     cmerr = ChangePixPat( *curentPixPat ) ;                // match curent
  431.     SetError( cmerr ) ;
  432. }
  433. /*------------------------------------------------------------------------------*\
  434.     UnChangePortPixPat
  435.  *------------------------------------------------------------------------------*
  436.         This routine un-changes one of the PixPats in the current CGrafPort by
  437.         by restoring the appropriate buffered global.
  438. \*------------------------------------------------------------------------------*/
  439. static void UnChangePortPixPat ( short which )
  440. {
  441.     PixPatHandle    *curentPixPat ;
  442.     PixPatHandle    *lastPixPat ;
  443.  
  444.     if (gDrawMode != kCheck)                            // if these two conditions are true
  445.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  446.     
  447.     switch (which)
  448.     {
  449.         case kPenPixPat :
  450.             curentPixPat = &(((CGrafPtr)qd.thePort)->pnPixPat) ;
  451.             lastPixPat = &gLastPenPixPat ;
  452.             break ;
  453.         case kFillPixPat :
  454.             curentPixPat = &(((CGrafPtr)qd.thePort)->fillPixPat) ;
  455.             lastPixPat = &gLastFillPixPat ;
  456.             break ;
  457.         case kBackPixPat :
  458.             curentPixPat = &(((CGrafPtr)qd.thePort)->bkPixPat) ;
  459.             lastPixPat = &gLastBackPixPat ;
  460.             break ;
  461.         default :
  462.             return ;
  463.             break ;
  464.     }
  465.  
  466.     if ( (***lastPixPat).patType == 0 )
  467.     {
  468.         UnChangePortColor( kForeColor ) ;
  469.         UnChangePortColor( kBackColor ) ;
  470.     }
  471.  
  472.     CopyPixPat( *lastPixPat, *curentPixPat ) ;                    // curent = last
  473. }
  474.  
  475.  
  476. ////////////////////////////////////////////////////////////////////////////////
  477.  
  478.  
  479. /*------------------------------------------------------------------------------*\
  480.     ChangePortPixPatForVerb
  481.  *------------------------------------------------------------------------------*
  482.         This routine changes one of the PixPats in the current CGrafPort by
  483.         calling ChangePortPixPat().  For example, if the GrafVerb verb==erase
  484.         then the port's kBackPixPat is changed.
  485. \*------------------------------------------------------------------------------*/
  486. static void ChangePortPixPatForVerb ( GrafVerb verb )
  487. {
  488.     if (gDrawMode != kCheck)                            // if these two conditions are true
  489.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  490.     switch (verb)
  491.     {
  492.         case kQDGrafVerbFrame:
  493.         case kQDGrafVerbPaint: /* Framed and painted objects are drawn in the pen PixPat. */
  494.                 ChangePortPixPat( kPenPixPat ) ;
  495.                 break;
  496.         case kQDGrafVerbErase: /* Erased objects are drawn in the background PixPat. */
  497.                 ChangePortPixPat( kBackPixPat ) ;
  498.                 break;
  499.         case kQDGrafVerbFill:    /* Filled objects are drawn in the fill PixPat. */
  500.                 ChangePortPixPat( kFillPixPat ) ;
  501.                 break;
  502.     }
  503. }
  504. /*------------------------------------------------------------------------------*\
  505.     UnChangePortPixPatForVerb
  506.  *------------------------------------------------------------------------------*
  507.         This routine un-changes one of the PixPats in the current CGrafPort by
  508.         by calling UnChangePortPixPat().
  509. \*------------------------------------------------------------------------------*/
  510. static void UnChangePortPixPatForVerb ( GrafVerb verb )
  511. {
  512.     if (gDrawMode != kCheck)                            // if these two conditions are true
  513.     if (gMatchingEnabled == false) return ;                // then no work needs to be done
  514.     switch (verb)
  515.     {
  516.         case kQDGrafVerbFrame:
  517.         case kQDGrafVerbPaint: /* Framed and painted objects are drawn in the pen PixPat. */
  518.                 UnChangePortPixPat( kPenPixPat ) ;
  519.                 break;
  520.         case kQDGrafVerbErase: /* Erased objects are drawn in the background PixPat. */
  521.                 UnChangePortPixPat( kBackPixPat ) ;
  522.                 break;
  523.         case kQDGrafVerbFill:    /* Filled objects are drawn in the fill PixPat. */
  524.                 UnChangePortPixPat( kFillPixPat ) ;
  525.                 break;
  526.     }
  527. }
  528.  
  529.  
  530.  
  531. /**\
  532. |**| ==============================================================================
  533. |**| BOTTLENECK ROUTINES
  534. |**| ==============================================================================
  535. \**/
  536.  
  537.  
  538. static pascal void TextProc ( short byteCount, Ptr textAddr, Point numer, Point denom )
  539. {    /* Text is drawn with the foreground and background colors.*/
  540.     ChangePortColor( kForeColor ) ;
  541.     ChangePortColor( kBackColor ) ;
  542.     StdText( byteCount, textAddr, numer, denom ) ;
  543.     UnChangePortColor( kForeColor ) ;
  544.     UnChangePortColor( kBackColor ) ;
  545. }
  546.  
  547.  
  548. static pascal void LineProc ( Point endPoint )
  549. {    /* Lines are drawn with the pen PixPat. */
  550.     ChangePortPixPat( kPenPixPat ) ;
  551.     StdLine( endPoint ) ;
  552.     UnChangePortPixPat( kPenPixPat ) ;
  553. }
  554.  
  555.  
  556. static pascal void RectProc ( GrafVerb verb, Rect *r )
  557. {    // Rects are drawn according to the GrafVerb
  558.     ChangePortPixPatForVerb( verb ) ;
  559.     StdRect( verb, r ) ;
  560.     UnChangePortPixPatForVerb( verb ) ;
  561. }
  562.  
  563.  
  564. static pascal void RRectProc ( GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight )
  565. {    // RRects are drawn according to the GrafVerb
  566.     ChangePortPixPatForVerb( verb ) ;
  567.     StdRRect( verb, r, ovalWidth, ovalHeight ) ;
  568.     UnChangePortPixPatForVerb( verb ) ;
  569. }
  570.  
  571.  
  572. static pascal void OvalProc ( GrafVerb verb, Rect *r )
  573. {    // Ovals are drawn according to the GrafVerb
  574.     ChangePortPixPatForVerb( verb ) ;
  575.     StdOval( verb, r ) ;
  576.     UnChangePortPixPatForVerb( verb ) ;
  577. }
  578.  
  579.  
  580. static pascal void ArcProc ( GrafVerb verb, Rect *r, short startAngle, short arcAngle )
  581. {    // Arcs are drawn according to the GrafVerb
  582.     ChangePortPixPatForVerb( verb ) ;
  583.     StdArc( verb, r, startAngle, arcAngle ) ;
  584.     UnChangePortPixPatForVerb( verb ) ;
  585. }
  586.  
  587.  
  588. static pascal void PolyProc ( GrafVerb verb, PolyHandle poly )
  589. {    // Polys are drawn according to the GrafVerb
  590.     ChangePortPixPatForVerb( verb ) ;
  591.     StdPoly( verb, poly ) ;
  592.     UnChangePortPixPatForVerb( verb ) ;
  593. }
  594.  
  595.  
  596. static pascal void RgnProc ( GrafVerb verb, RgnHandle rgn )
  597. {    // Regions are drawn according to the GrafVerb
  598.     ChangePortPixPatForVerb( verb ) ;
  599.     StdRgn( verb, rgn ) ;
  600.     UnChangePortPixPatForVerb( verb ) ;
  601. }
  602.  
  603.  
  604. static pascal void BitsProc ( BitMap *bitPtr, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn )
  605. {
  606.     CMError            cmerr ;
  607.     PixMapPtr        pixMapPtr;
  608.     short            rowBytes;
  609.     unsigned long    ticks;
  610.  
  611.     /* Get the PixMap that we are about to draw.
  612.        SrcBits might be a BitMap, or one of 
  613.        two different kinds of PixMap pointers.  */
  614.         
  615.     rowBytes = (*bitPtr).rowBytes;                        /* local copy of rowBytes */
  616.  
  617.     // Update the number of pixels we're processing
  618.     gPixels +=     (srcRect->right - srcRect->left) *
  619.                 (srcRect->bottom - srcRect->top);
  620.     
  621.     if (rowBytes & 0x8000)                                /* if high bit set then its a pixmap */
  622.     {
  623.         if (rowBytes & 0x4000)                            /* next to high bit set? */
  624.         {
  625.             HLock( (Handle) (*((PixMapHandle*)bitPtr)) ) ;
  626.             pixMapPtr = (**((PixMapHandle*)bitPtr)) ;    /* bitPtr is a ptr to a PixMap handle */
  627.         }
  628.         else
  629.             pixMapPtr = (PixMapPtr) bitPtr;                /* bitPtr is a ptr to a PixMap */
  630.             
  631.  
  632.         if (gDrawMode == kCheck)
  633.         {
  634.             BitMap            bm;
  635.  
  636.             // create bitmap
  637.             bm.bounds = (*bitPtr).bounds ;
  638.             bm.rowBytes = CalculateRowBytesFromRect( &(bm.bounds), 1 ) ;
  639.             bm.baseAddr = NewPtrClear( bm.rowBytes*(bm.bounds.bottom-bm.bounds.top) );
  640.             
  641.             if (gMatchingEnabled)
  642.             {
  643.                 ticks = TickCount();
  644.                 cmerr = CWCheckPixMap( gCW, pixMapPtr, nil, nil, (BitMap *)&bm) ;
  645.                 gTicks += TickCount() - ticks;
  646.                 SetError( cmerr ) ;
  647.             }
  648.             // else leave offscreen as all-white
  649.             
  650.             StdBits( (BitMap *)&bm, srcRect, dstRect, mode, maskRgn) ;
  651.             
  652.             // dispose bitmap
  653.             DisposePtr( (Ptr)bm.baseAddr );
  654.         }
  655.         else 
  656.         {
  657.             if (gMatchingEnabled)
  658.             {
  659.                 ticks = TickCount();
  660.                 cmerr = CWMatchPixMap( gCW, pixMapPtr, nil, nil ) ;
  661.                 gTicks += TickCount() - ticks;
  662.                 SetError( cmerr ) ;
  663.             }
  664.             StdBits( bitPtr, srcRect, dstRect, mode, maskRgn) ;
  665.         }
  666.         
  667.         if (rowBytes & 0x4000)                            /* next to high bit set? */
  668.             HUnlock( (Handle) (*((PixMapHandle*)bitPtr)) ) ;
  669.     }
  670.     else
  671.     {    /* It's just a BitMap; it will use the background and foreground colors. */
  672.         ChangePortColor( kForeColor ) ;
  673.         ChangePortColor( kBackColor ) ;
  674.         StdBits( bitPtr, srcRect, dstRect, mode, maskRgn) ;
  675.         UnChangePortColor( kForeColor ) ;
  676.         UnChangePortColor( kBackColor ) ;
  677.     }
  678. }
  679.  
  680. /* Routine - CalculateRowbytesFromRect */
  681. /* Given a pointer to a rectangle and number of bits per pixel, this routine calculates
  682.    the row bytes of an image */
  683.  
  684.  
  685. short CalculateRowBytesFromRect(Rect *theRect, short pixelSize) 
  686. {
  687.      short rowBytes ;
  688.     short imageWidth ;
  689.     
  690.     imageWidth = theRect->right - theRect->left ;
  691.     rowBytes = (pixelSize * ((imageWidth + 15)/16)) * 2 ;
  692.     return rowBytes ;
  693. }
  694.  
  695.  
  696. static pascal void CommentProc ( short kind, short dataSize, Handle dataHandle )
  697. {
  698.     long            selector ;
  699.     CMProfileRef    srceProf ;
  700.     CMError            cmerr ;
  701.     
  702.     switch (kind)
  703.     {
  704.         case cmBeginProfile :
  705.             gCount ++ ;                                // we found a version 1 profile
  706.             if ( gMatchingEnabled == false ) break ;
  707.             cmerr = GetIndexedProfileFromPicHandle( gPict, gCount, &srceProf, nil ) ;
  708.             SetError( cmerr ) ;
  709.             BuildColorWorld( srceProf ) ;
  710.             cmerr = CMCloseProfile( srceProf ) ;
  711.             break ;
  712.  
  713.         case cmEndProfile :
  714.             if ( gMatchingEnabled == false ) break ;
  715.             BuildColorWorld( gSrceProf ) ;
  716.             break ;
  717.             
  718.         case cmEnableMatching :
  719.             gMatchingEnabled = true ;
  720.             break ;
  721.             
  722.         case cmDisableMatching :
  723.             if ( gMatchingEnabled == false ) break ;
  724.             gMatchingEnabled = false ;
  725.             break ;
  726.             
  727.         case cmComment:
  728.             if ( dataSize <= 4 ) break;                // dataSize too small for selector so break
  729.             selector = *((long *)(*dataHandle)) ;    // get the selector from 1st long in data
  730.             switch (selector)
  731.             {
  732.                 case cmBeginProfileSel :
  733.                     gCount ++ ;                        // we found a version 2 profile
  734.                     if ( gMatchingEnabled == false ) break ;
  735.                     cmerr = GetIndexedProfileFromPicHandle( gPict, gCount, &srceProf, nil ) ;
  736.                     SetError( cmerr ) ;
  737.                     BuildColorWorld( srceProf ) ;
  738.                     cmerr = AppendProfileBuffers( srceProf ) ;
  739.                     cmerr = CMCloseProfile( srceProf ) ;
  740.                     break ;
  741.                     
  742.                 case cmProfileIdentifierSel :
  743.                     gCount ++ ;                        // we found a version 2 profile id
  744.                     if ( gMatchingEnabled == false ) break ;
  745.                     cmerr = GetIndexedProfileFromPicHandle( gPict, gCount, &srceProf, nil ) ;
  746.                     SetError( cmerr ) ;
  747.                     BuildColorWorld( srceProf ) ;
  748.                     cmerr = CMCloseProfile( srceProf ) ;
  749.                     break ;
  750.                     
  751.                 case cmContinueProfileSel :
  752.                 case cmEndProfileSel :
  753.                     break ;
  754.             }
  755.             break ;
  756.         
  757.         default:
  758.             StdComment( kind, dataSize, dataHandle ) ;
  759.             break ;
  760.     }        
  761. }
  762.  
  763.  
  764.  
  765. static void DisposeColorWorld ( void )
  766. {
  767.     if ( gCW ) CWDisposeColorWorld( gCW ) ;
  768.     gCW = nil ;
  769. }
  770.  
  771.  
  772. static void BuildColorWorld ( CMProfileRef srceProf )
  773. {
  774.     CMError                cmerr ;
  775.     CMConcatProfileSet    *profileSetPtr ;
  776.     CMProfileRef        foundProf=nil;
  777.     
  778.     DisposeColorWorld() ;
  779.     
  780.     // should check to see if the profs are kosher 
  781.     
  782.     if ( IsPseudoProfile(srceProf) )
  783.     {    //    search buffered profiles
  784.         HLock( (Handle)gProfileListHdl );
  785.         cmerr = PseudoProfileListSearch( srceProf, &foundProf,
  786.                                          *gProfileListHdl, gProfileListCount ) ;
  787.         if (cmerr || !foundProf)            //    if none found
  788.         {    //    search profiles folder
  789.             cmerr = PseudoProfileFolderSearch( srceProf, &foundProf) ;
  790.             if (cmerr || !foundProf)        //    if none found
  791.                 cmerr = CMGetSystemProfile(&foundProf) ;
  792.         }
  793.         if (!cmerr) srceProf = foundProf ;
  794.     }
  795.     
  796.     if ( gDrawMode==kMatch || gDrawMode==kCheck )
  797.     {
  798.         cmerr = NCWNewColorWorld( &gCW, srceProf, gDestProf ) ;
  799.     }
  800.     else     // ( gDrawMode==kProof)
  801.     {
  802.         profileSetPtr = (CMConcatProfileSet *)NewPtr( sizeof(CMConcatProfileSet) +
  803.                                                       2*sizeof(CMProfileRef) ) ;
  804.         // use the cmm of the dest profile
  805.         profileSetPtr->keyIndex = 1 ;
  806.         profileSetPtr->count = 3 ;
  807.         profileSetPtr->profileSet[0] = srceProf ;
  808.         profileSetPtr->profileSet[1] = gDestProf ;
  809.         profileSetPtr->profileSet[2] = gPrevProf ;
  810.         cmerr = CWConcatColorWorld( &gCW, profileSetPtr) ;
  811.         DisposePtr( (Ptr)profileSetPtr ) ;
  812.     }
  813.     
  814.     if (foundProf)
  815.         CMCloseProfile(foundProf) ;
  816.  
  817.     SetError( cmerr ) ;
  818.  
  819.     gLastForeColorNeedsUpdate = true ;
  820.     gLastBackColorNeedsUpdate = true ;
  821. }
  822.  
  823.  
  824. static OSErr AllocateProfileBuffers ( void )
  825. {
  826.     gProfileListHdl = (CMProfileRef**)NewHandle( 0 ) ;
  827.     if (gProfileListHdl==nil)
  828.         return MemError();
  829.         
  830.     gProfileListCount = 0 ;
  831.     return noErr ;
  832. }
  833. static OSErr AppendProfileBuffers ( CMProfileRef prof )
  834. {
  835.     OSErr err;
  836.     Size oldsize;
  837.     CMProfileRef newProf;
  838.     
  839.     oldsize = GetHandleSize((Handle)gProfileListHdl);
  840.     if (oldsize<0)
  841.         return oldsize;
  842.         
  843.     SetHandleSize( (Handle)gProfileListHdl, 
  844.                    oldsize + sizeof(CMProfileRef) );
  845.     err = MemError();
  846.     if (err) return err;
  847.     
  848.     err = ReOpenProfileRef( &newProf, prof ) ; 
  849.     if (err) return err;
  850.  
  851.     (*gProfileListHdl)[gProfileListCount] = newProf ;
  852.     gProfileListCount++;
  853.     return noErr ;
  854. }
  855. static void DisposeProfileBuffers ( void )
  856. {
  857.     long i;
  858.     for ( i=0; i<gProfileListCount; i++ )
  859.         CMCloseProfile( (*gProfileListHdl)[i]) ;
  860.     DisposeHandle( (Handle)gProfileListHdl ) ;
  861.     gProfileListCount = 0 ;
  862. }
  863.  
  864.  
  865. static OSErr AllocateMatchBuffers ( void )
  866. {
  867.     gLastForeColor            = gBlackRGB ;
  868.     gLastForeColorMatched    = gBlackRGB ;
  869.     gLastBackColor            = gWhiteRGB ;
  870.     gLastBackColorMatched    = gWhiteRGB ;
  871.     
  872.     gLastPenPixPat            = NewPixPat() ;
  873.     gLastFillPixPat            = NewPixPat() ;
  874.     gLastBackPixPat            = NewPixPat() ;
  875.  
  876.     gLastForeColorNeedsUpdate  = 
  877.     gLastBackColorNeedsUpdate  = true ;
  878.     return noErr ;
  879. }
  880. static void DisposeMatchBuffers ( void )
  881. {
  882.     DisposePixPat( gLastPenPixPat ) ;
  883.     DisposePixPat( gLastFillPixPat ) ;
  884.     DisposePixPat( gLastBackPixPat ) ;
  885. }
  886.  
  887.  
  888. static OSErr myDrawPicture ( PicHandle pict,
  889.                       CMProfileRef srceProf,
  890.                       CMProfileRef destProf,
  891.                       CMProfileRef prevProf,
  892.                       Rect *rect,
  893.                       unsigned long *ticks,
  894.                       unsigned long *pixels )
  895. {
  896.     OSErr            err = noErr ;
  897.     CQDProcs        procs ;
  898.     CQDProcsPtr        oldProcs ;
  899.  
  900.     SetStdCProcs(&procs) ;
  901.  
  902.     procs.textProc    = NewQDTextProc   ( TextProc    ) ;
  903.     procs.lineProc    = NewQDLineProc   ( LineProc    ) ;
  904.     procs.rectProc    = NewQDRectProc   ( RectProc    ) ;
  905.     procs.rRectProc   = NewQDRRectProc  ( RRectProc   ) ;
  906.     procs.ovalProc    = NewQDOvalProc   ( OvalProc    ) ;
  907.     procs.arcProc     = NewQDArcProc    ( ArcProc     ) ;
  908.     procs.polyProc    = NewQDPolyProc   ( PolyProc    ) ;
  909.     procs.rgnProc     = NewQDRgnProc    ( RgnProc     ) ;
  910.     procs.bitsProc    = NewQDBitsProc   ( BitsProc    ) ;
  911.     procs.commentProc = NewQDCommentProc( CommentProc ) ;
  912.  
  913.     oldProcs = (*(CGrafPtr)qd.thePort).grafProcs ;     // must be a color port
  914.     (*(CGrafPtr)qd.thePort).grafProcs = &procs ;     // must be a color port
  915.  
  916.     if (!err) err = AllocateMatchBuffers() ;
  917.     if (!err) err = AllocateProfileBuffers() ;
  918.     if (!err) 
  919.     {
  920.         gMatchingEnabled = true ;
  921.         gError = noErr ;
  922.         gPict = pict ;
  923.         gCount = 0 ;
  924.         gTicks = 0 ;
  925.         gPixels = 0;
  926.         gSrceProf = srceProf ;
  927.         gDestProf = destProf ;
  928.         gPrevProf = prevProf ;
  929.         if ( srceProf==nil )    CMGetSystemProfile( &gSrceProf ) ;
  930.         if ( destProf==nil )    CMGetSystemProfile( &gDestProf ) ;
  931.         if ( prevProf==nil )    CMGetSystemProfile( &gPrevProf ) ;
  932.         BuildColorWorld( gSrceProf ) ;
  933.         
  934.             HLock( (Handle) pict ) ;
  935.             DrawPicture( pict, rect ) ;
  936.             HUnlock( (Handle) pict ) ;
  937.     
  938.         err = gError ;
  939.         DisposeColorWorld() ;
  940.         if ( srceProf==nil )    CMCloseProfile( gSrceProf ) ;
  941.         if ( destProf==nil )    CMCloseProfile( gDestProf ) ;
  942.         if ( prevProf==nil )    CMCloseProfile( gPrevProf ) ;
  943.  
  944.         DisposeMatchBuffers() ;
  945.         DisposeProfileBuffers() ;
  946.     }
  947.         
  948.     (*(CGrafPtr)qd.thePort).grafProcs = oldProcs ;     // must be a color port
  949.     
  950.     DisposeRoutineDescriptor( procs.textProc    ) ;
  951.     DisposeRoutineDescriptor( procs.lineProc    ) ;
  952.     DisposeRoutineDescriptor( procs.rectProc    ) ;
  953.     DisposeRoutineDescriptor( procs.rRectProc   ) ;
  954.     DisposeRoutineDescriptor( procs.ovalProc    ) ;
  955.     DisposeRoutineDescriptor( procs.arcProc     ) ;
  956.     DisposeRoutineDescriptor( procs.polyProc    ) ;
  957.     DisposeRoutineDescriptor( procs.rgnProc     ) ;
  958.     DisposeRoutineDescriptor( procs.bitsProc    ) ;
  959.     DisposeRoutineDescriptor( procs.commentProc ) ;
  960.     
  961.     // Update the ticks parameter, if it was passed
  962.     if (ticks)
  963.     {
  964.         if (err)
  965.             *ticks = 0;
  966.         else
  967.             *ticks = gTicks;
  968.     }
  969.     
  970.     // Update the pixel count parameter, if it was passed
  971.     if (pixels)
  972.     {
  973.         if (err)
  974.             *pixels = 0;
  975.         else
  976.             *pixels = gPixels;
  977.     }
  978.     
  979.     return err;
  980. }
  981.  
  982.  
  983. /**\
  984. |**| ==============================================================================
  985. |**| PUBLIC FUNCTIONS
  986. |**| ==============================================================================
  987. \**/
  988.  
  989.  
  990. OSErr myDrawMatchedPicture ( PicHandle pict,
  991.                              CMProfileRef srceProf,
  992.                              CMProfileRef prevProf,
  993.                              Rect *rect,
  994.                              unsigned long *ticks,
  995.                              unsigned long *pixels )
  996. {
  997.     gDrawMode = kMatch ;
  998.     return myDrawPicture( pict, srceProf, prevProf, nil, rect, ticks, pixels ) ;
  999. }
  1000.  
  1001.  
  1002. OSErr myDrawProofedPicture ( PicHandle pict,
  1003.                              CMProfileRef srceProf,
  1004.                              CMProfileRef destProf,
  1005.                              CMProfileRef prevProf,
  1006.                              Rect *rect,
  1007.                              unsigned long *ticks,
  1008.                              unsigned long *pixels )
  1009. {
  1010.     gDrawMode = kProof ;
  1011.     return myDrawPicture( pict, srceProf, destProf, prevProf, rect, ticks, pixels ) ;
  1012. }
  1013.  
  1014.  
  1015. OSErr myDrawCheckedPicture ( PicHandle pict,
  1016.                              CMProfileRef srceProf,
  1017.                              CMProfileRef destProf,
  1018.                              Rect *rect,
  1019.                              unsigned long *ticks,
  1020.                              unsigned long *pixels )
  1021. {
  1022.     gDrawMode = kCheck ;
  1023.     return myDrawPicture( pict, srceProf, destProf, nil, rect, ticks, pixels ) ;
  1024. }
  1025.